#!/usr/bin/env python2
# -*- coding: utf-8 -*-

from __future__ import division

import os
import sys
import time
import json
import pygame
import random
import select
import traceback

if os.getenv('sdlttf'):
    import draw_sdlttf as draw
else:
    import draw_cairo as draw

from config import Config
from editor import Editor
from game import Game
from help import Help
from problem import Problem
from submit import Submit


class Vimim(object):
    SAVE = ['config_app', 'editor_app', 'game_app', 'help_app', 'problem_app',
            'submit_app', 'win_warn']

    def __init__(self, savename=None):
        self.window = draw.Window()
        self.window.start = self.start
        self.window.draw = self.draw
        self.window.react = self.react
        self.window.draw_terminal = draw.draw_terminal

        self.last_idle = 0
        self.darkness = 0

        self.task_names = [
            'kompilovatelne', 'zero', 'hello', 'stream', 'sucet', 'sum',
            'factorial', 'fibonacci', 'reverse', 'srnka', 'popolvar',
            'lorem_ipsum', 'median', 'mod9', 'rot', 'difference',
        ]

        self.win_warn = 12
        self.config_app = Config(self)
        self.editor_app = Editor(self)
        self.game_app = Game(self)
        self.help_app = Help(self)
        self.problem_app = Problem(self)
        self.submit_app = Submit(self)
        self.app = self.editor_app

        self.savename = savename
        if savename and os.path.exists(savename):
            self.load(savename)

        (r, w) = os.pipe()
        os.dup2(r, 0)
        os.close(r)
        self.poll = select.poll()
        self.poll.register(0, select.POLLIN)

    def load(self, filename):
        with open(filename) as f: content = json.load(f, 'utf-8')
        self.load_content(content)

    def load_content(self, content):
        for key in content:
            if '.' in key:
                appname, propname = key.split('.')
                setattr(getattr(self, appname), propname, content[key])
            else:
                setattr(self, key, content[key])

    def save(self, filename=None):
        content = {}
        for key in self.SAVE:
            if key.endswith('_app'):
                app = getattr(self, key)
                for key2 in app.SAVE:
                    content[key + '.' + key2] = getattr(app, key2)
            else:
                content[key] = getattr(self, key)
        if filename:
            with open(filename, 'w') as f:
                json.dump(content, f)
        return content

    def run(self):
        w = 720
        h = 425
        self.window.run(w, h, 'vimim', bool(os.getenv('FULLSCREEN')))

    def start(self):
        pygame.key.set_repeat(500, 30)   # SDL defaults

    def draw(self, ctx):
        self.app.draw(ctx)

        now = time.time()
        if now > self.last_idle + 1.0/20:
            self.last_idle = now
            self.app.idle()

            sys.stdout.flush()

            if self.poll.poll(0):
                received = os.read(0, 4*1024*1024)
                print repr(received)
                try:
                    self.load_content(json.loads(received.strip()))
                except Exception:
                    traceback.print_exc()

    def react(self, event):
        if event.type == pygame.QUIT:
            self.window.running = False
        if event.type == pygame.KEYDOWN:
            #print (event.unicode, event.key, event.mod)
            self.app.keydown(self.normalize_key(event))

    def pay(self, price):
        if self.config_app.credits < price: return False
        self.config_app.credits -= price
        return True

    _keys_table = {
        pygame.K_LEFT:      u'\u2190',
        pygame.K_UP:        u'\u2191',
        pygame.K_RIGHT:     u'\u2192',
        pygame.K_DOWN:      u'\u2193',
        pygame.K_HOME:      u'\u25C0',
        pygame.K_END:       u'\u25B6',
        pygame.K_PAGEUP:    u'\u25B2',
        pygame.K_PAGEDOWN:  u'\u25BC',
        pygame.K_BACKSPACE: u'\u2665',
        pygame.K_DELETE:    u'\u2717',
    }
    def normalize_key(self, event):
        if event.key in self._keys_table:
            code = self._keys_table[event.key]
        elif event.unicode == u'\x1f':
            code = self._keys_table[pygame.K_DELETE]
        elif event.unicode == u'\r':
            code = u'\n'
        elif pygame.K_F1 <= event.key <= pygame.K_F12:
            code = u'<F%d>' % (event.key - pygame.K_F1 + 1)
        else:
            code = event.unicode
        return pygame.event.Event(pygame.KEYDOWN,
            unicode=code, key=event.key, mod=event.mod)

    @property
    def features(self):
        return self.config_app.features

    def bell(self):
        pass   # TODO

    @property
    def have_status_bar(self):
        return not self.features['nostatus']

    def draw_generic_status_bar(self, screen):
        screen.recolor(0, 80, 24, (1, 1, 1), None)

        if self.game_app.x <= self.win_warn and int(time.time() / 0.2) % 2:
            text = u"!!! VYHRÁVAŠ !!!"
            screen.recolor(50, 50+len(text), 24, (0, 1, 0), None)
            screen.write(50, 24, text)

        screen.write(70, 24, u"%d Kr" % self.config_app.credits)
        if self.config_app.credits < 50:
            screen.recolor(70, 80, 24, (1, 0, 0), None)

    def postprocess_screen(self, screen, ingame=False):
        letters = 'abcdefghijklmnopqrstuvwxyz'
        retters = letters[13:] + letters[:13]
        rot13 = dict(zip(letters, retters) + zip(letters.upper(), retters.upper()))

        if self.features['rot13'] and not ingame:
            for y in xrange(25):
                for x in xrange(80):
                    screen.chars[y][x] = rot13.get(screen.chars[y][x], screen.chars[y][x])

        if time.time() < self.game_app.win_time:
            self.game_app.congratulate(screen)

        if self.features['large'] and not ingame:
            for y in xrange(25):
                for x in xrange(80):
                    screen.chars[y][x] = screen.chars[y][x].upper()

        if self.features['green']:
            screen.mainbg = (0, 1, 0)
            for y in xrange(25):
                for x in xrange(80):
                    if screen.bg[y][x]:
                        screen.bg[y][x] = (1, 0, 0)
                        screen.fg[y][x] = (0, 1, 0)
                    else:
                        screen.bg[y][x] = None
                        screen.fg[y][x] = (1, 0, 0)

        if self.features['180']:
            screen.flip = True

        if time.time() < self.darkness and not ingame:
            screen.mainbg = (0, 0, 0)
            for y in xrange(25):
                for x in xrange(80):
                    screen.bg[y][x] = None
                    screen.fg[y][x] = (0, 0, 0)


if __name__ == '__main__':
    Vimim(savename=sys.argv[1] if sys.argv[1:] else None).run()
